From 101c0df79ca31aa950c340812f09cdeadbb89732 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 13 Apr 2023 20:24:35 -0600 Subject: service: nfp: Use an unique interface --- src/core/CMakeLists.txt | 4 +- src/core/hle/service/nfp/nfp.cpp | 187 +++++++- src/core/hle/service/nfp/nfp_interface.cpp | 643 +++++++++++++++++++++++++++ src/core/hle/service/nfp/nfp_interface.h | 63 +++ src/core/hle/service/nfp/nfp_user.cpp | 672 ----------------------------- src/core/hle/service/nfp/nfp_user.h | 63 --- 6 files changed, 894 insertions(+), 738 deletions(-) create mode 100644 src/core/hle/service/nfp/nfp_interface.cpp create mode 100644 src/core/hle/service/nfp/nfp_interface.h delete mode 100644 src/core/hle/service/nfp/nfp_user.cpp delete mode 100644 src/core/hle/service/nfp/nfp_user.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4e677f287..8817a99c9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -570,10 +570,10 @@ add_library(core STATIC hle/service/nfp/nfp.h hle/service/nfp/nfp_device.cpp hle/service/nfp/nfp_device.h + hle/service/nfp/nfp_interface.cpp + hle/service/nfp/nfp_interface.h hle/service/nfp/nfp_result.h hle/service/nfp/nfp_types.h - hle/service/nfp/nfp_user.cpp - hle/service/nfp/nfp_user.h hle/service/ngct/ngct.cpp hle/service/ngct/ngct.h hle/service/nifm/nifm.cpp diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index e262dc2f2..e57e932c8 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -4,11 +4,138 @@ #include "common/logging/log.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nfp/nfp.h" -#include "core/hle/service/nfp/nfp_user.h" +#include "core/hle/service/nfp/nfp_interface.h" #include "core/hle/service/server_manager.h" namespace Service::NFP { +class IUser final : public Interface { +public: + explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IUser::Initialize, "Initialize"}, + {1, &IUser::Finalize, "Finalize"}, + {2, &IUser::ListDevices, "ListDevices"}, + {3, &IUser::StartDetection, "StartDetection"}, + {4, &IUser::StopDetection, "StopDetection"}, + {5, &IUser::Mount, "Mount"}, + {6, &IUser::Unmount, "Unmount"}, + {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, + {8, &IUser::GetApplicationArea, "GetApplicationArea"}, + {9, &IUser::SetApplicationArea, "SetApplicationArea"}, + {10, &IUser::Flush, "Flush"}, + {11, &IUser::Restore, "Restore"}, + {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, + {13, &IUser::GetTagInfo, "GetTagInfo"}, + {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, + {15, &IUser::GetCommonInfo, "GetCommonInfo"}, + {16, &IUser::GetModelInfo, "GetModelInfo"}, + {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, + {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {19, &IUser::GetState, "GetState"}, + {20, &IUser::GetDeviceState, "GetDeviceState"}, + {21, &IUser::GetNpadId, "GetNpadId"}, + {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, + {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, + {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class ISystem final : public Interface { +public: + explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "InitializeSystem"}, + {1, nullptr, "FinalizeSystem"}, + {2, &ISystem::ListDevices, "ListDevices"}, + {3, &ISystem::StartDetection, "StartDetection"}, + {4, &ISystem::StopDetection, "StopDetection"}, + {5, &ISystem::Mount, "Mount"}, + {6, &ISystem::Unmount, "Unmount"}, + {10, &ISystem::Flush, "Flush"}, + {11, &ISystem::Restore, "Restore"}, + {12, &ISystem::CreateApplicationArea, "CreateApplicationArea"}, + {13, &ISystem::GetTagInfo, "GetTagInfo"}, + {14, &ISystem::GetRegisterInfo, "GetRegisterInfo"}, + {15, &ISystem::GetCommonInfo, "GetCommonInfo"}, + {16, &ISystem::GetModelInfo, "GetModelInfo"}, + {17, &ISystem::AttachActivateEvent, "AttachActivateEvent"}, + {18, &ISystem::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {19, &ISystem::GetState, "GetState"}, + {20, &ISystem::GetDeviceState, "GetDeviceState"}, + {21, &ISystem::GetNpadId, "GetNpadId"}, + {23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, + {100, nullptr, "Format"}, + {101, nullptr, "GetAdminInfo"}, + {102, nullptr, "GetRegisterInfoPrivate"}, + {103, nullptr, "SetRegisterInfoPrivate"}, + {104, nullptr, "DeleteRegisterInfo"}, + {105, nullptr, "DeleteApplicationArea"}, + {106, nullptr, "ExistsApplicationArea"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IDebug final : public Interface { +public: + explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "InitializeDebug"}, + {1, nullptr, "FinalizeDebug"}, + {2, &IDebug::ListDevices, "ListDevices"}, + {3, &IDebug::StartDetection, "StartDetection"}, + {4, &IDebug::StopDetection, "StopDetection"}, + {5, &IDebug::Mount, "Mount"}, + {6, &IDebug::Unmount, "Unmount"}, + {7, &IDebug::OpenApplicationArea, "OpenApplicationArea"}, + {8, &IDebug::GetApplicationArea, "GetApplicationArea"}, + {9, &IDebug::SetApplicationArea, "SetApplicationArea"}, + {10, &IDebug::Flush, "Flush"}, + {11, &IDebug::Restore, "Restore"}, + {12, &IDebug::CreateApplicationArea, "CreateApplicationArea"}, + {13, &IDebug::GetTagInfo, "GetTagInfo"}, + {14, &IDebug::GetRegisterInfo, "GetRegisterInfo"}, + {15, &IDebug::GetCommonInfo, "GetCommonInfo"}, + {16, &IDebug::GetModelInfo, "GetModelInfo"}, + {17, &IDebug::AttachActivateEvent, "AttachActivateEvent"}, + {18, &IDebug::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {19, &IDebug::GetState, "GetState"}, + {20, &IDebug::GetDeviceState, "GetDeviceState"}, + {21, &IDebug::GetNpadId, "GetNpadId"}, + {22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"}, + {23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, + {24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"}, + {100, nullptr, "Format"}, + {101, nullptr, "GetAdminInfo"}, + {102, nullptr, "GetRegisterInfoPrivate"}, + {103, nullptr, "SetRegisterInfoPrivate"}, + {104, nullptr, "DeleteRegisterInfo"}, + {105, nullptr, "DeleteApplicationArea"}, + {106, nullptr, "ExistsApplicationArea"}, + {200, nullptr, "GetAll"}, + {201, nullptr, "SetAll"}, + {202, nullptr, "FlushDebug"}, + {203, nullptr, "BreakTag"}, + {204, nullptr, "ReadBackupData"}, + {205, nullptr, "WriteBackupData"}, + {206, nullptr, "WriteNtf"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + class IUserManager final : public ServiceFramework { public: explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} { @@ -37,10 +164,68 @@ private: std::shared_ptr user_interface; }; +class ISystemManager final : public ServiceFramework { +public: + explicit ISystemManager(Core::System& system_) : ServiceFramework{system_, "nfp:sys"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISystemManager::CreateSystemInterface, "CreateSystemInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void CreateSystemInterface(HLERequestContext& ctx) { + LOG_DEBUG(Service_NFP, "called"); + + if (system_interface == nullptr) { + system_interface = std::make_shared(system); + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system_interface); + } + + std::shared_ptr system_interface; +}; + +class IDebugManager final : public ServiceFramework { +public: + explicit IDebugManager(Core::System& system_) : ServiceFramework{system_, "nfp:dbg"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IDebugManager::CreateDebugInterface, "CreateDebugInterface"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void CreateDebugInterface(HLERequestContext& ctx) { + LOG_DEBUG(Service_NFP, "called"); + + if (system_interface == nullptr) { + system_interface = std::make_shared(system); + } + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(system_interface); + } + + std::shared_ptr system_interface; +}; + void LoopProcess(Core::System& system) { auto server_manager = std::make_unique(system); server_manager->RegisterNamedService("nfp:user", std::make_shared(system)); + server_manager->RegisterNamedService("nfp:sys", std::make_shared(system)); + server_manager->RegisterNamedService("nfp:dbg", std::make_shared(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp new file mode 100644 index 000000000..e131703cb --- /dev/null +++ b/src/core/hle/service/nfp/nfp_interface.cpp @@ -0,0 +1,643 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hid/hid_types.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/nfp/nfp_device.h" +#include "core/hle/service/nfp/nfp_interface.h" +#include "core/hle/service/nfp/nfp_result.h" + +namespace Service::NFP { + +Interface::Interface(Core::System& system_, const char* name) + : ServiceFramework{system_, name}, service_context{system_, service_name} { + availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); + + for (u32 device_index = 0; device_index < 10; device_index++) { + devices[device_index] = + std::make_shared(Core::HID::IndexToNpadIdType(device_index), system, + service_context, availability_change_event); + } +} + +Interface::~Interface() { + availability_change_event->Close(); +} + +void Interface::Initialize(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + state = State::Initialized; + + for (auto& device : devices) { + device->Initialize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void Interface::Finalize(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + state = State::NonInitialized; + + for (auto& device : devices) { + device->Finalize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void Interface::ListDevices(HLERequestContext& ctx) { + LOG_DEBUG(Service_NFP, "called"); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + if (!ctx.CanWriteBuffer()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + if (ctx.GetWriteBufferSize() == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + std::vector nfp_devices; + const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements(); + + for (const auto& device : devices) { + if (nfp_devices.size() >= max_allowed_devices) { + continue; + } + if (device->GetCurrentState() != DeviceState::Unavailable) { + nfp_devices.push_back(device->GetHandle()); + } + } + + if (nfp_devices.empty()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + ctx.WriteBuffer(nfp_devices); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast(nfp_devices.size())); +} + +void Interface::StartDetection(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto nfp_protocol{rp.PopEnum()}; + LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->StartDetection(nfp_protocol); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::StopDetection(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->StopDetection(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::Mount(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto model_type{rp.PopEnum()}; + const auto mount_target{rp.PopEnum()}; + LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle, + model_type, mount_target); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->Mount(mount_target); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::Unmount(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->Unmount(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::OpenApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto access_id{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->OpenApplicationArea(access_id); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto data_size = ctx.GetWriteBufferSize(); + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + if (!ctx.CanWriteBuffer()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + std::vector data(data_size); + const auto result = device.value()->GetApplicationArea(data); + ctx.WriteBuffer(data); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.Push(static_cast(data_size)); +} + +void Interface::SetApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto data{ctx.ReadBuffer()}; + LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size()); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + if (!ctx.CanReadBuffer()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->SetApplicationArea(data); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::Flush(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->Flush(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::Restore(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->RestoreAmiibo(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::CreateApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto access_id{rp.Pop()}; + const auto data{ctx.ReadBuffer()}; + LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, + access_id, data.size()); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + if (!ctx.CanReadBuffer()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->CreateApplicationArea(access_id, data); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetTagInfo(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + TagInfo tag_info{}; + const auto result = device.value()->GetTagInfo(tag_info); + ctx.WriteBuffer(tag_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetRegisterInfo(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + RegisterInfo register_info{}; + const auto result = device.value()->GetRegisterInfo(register_info); + ctx.WriteBuffer(register_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetCommonInfo(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + CommonInfo common_info{}; + const auto result = device.value()->GetCommonInfo(common_info); + ctx.WriteBuffer(common_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetModelInfo(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + ModelInfo model_info{}; + const auto result = device.value()->GetModelInfo(model_info); + ctx.WriteBuffer(model_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::AttachActivateEvent(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(device.value()->GetActivateEvent()); +} + +void Interface::AttachDeactivateEvent(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(device.value()->GetDeactivateEvent()); +} + +void Interface::GetState(HLERequestContext& ctx) { + LOG_DEBUG(Service_NFP, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(state); +} + +void Interface::GetDeviceState(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(device.value()->GetCurrentState()); +} + +void Interface::GetNpadId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(device.value()->GetNpadId()); +} + +void Interface::GetApplicationAreaSize(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(device.value()->GetApplicationAreaSize()); +} + +void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(availability_change_event->GetReadableEvent()); +} + +void Interface::RecreateApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto access_id{rp.Pop()}; + const auto data{ctx.ReadBuffer()}; + LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, + access_id, data.size()); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->RecreateApplicationArea(access_id, data); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +std::optional> Interface::GetNfpDevice(u64 handle) { + for (auto& device : devices) { + if (device->GetHandle() == handle) { + return device; + } + } + return std::nullopt; +} + +} // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_interface.h b/src/core/hle/service/nfp/nfp_interface.h new file mode 100644 index 000000000..11f29c2ba --- /dev/null +++ b/src/core/hle/service/nfp/nfp_interface.h @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::NFP { +class NfpDevice; + +class Interface : public ServiceFramework { +public: + explicit Interface(Core::System& system_, const char* name); + ~Interface() override; + + void Initialize(HLERequestContext& ctx); + void Finalize(HLERequestContext& ctx); + void ListDevices(HLERequestContext& ctx); + void StartDetection(HLERequestContext& ctx); + void StopDetection(HLERequestContext& ctx); + void Mount(HLERequestContext& ctx); + void Unmount(HLERequestContext& ctx); + void OpenApplicationArea(HLERequestContext& ctx); + void GetApplicationArea(HLERequestContext& ctx); + void SetApplicationArea(HLERequestContext& ctx); + void Flush(HLERequestContext& ctx); + void Restore(HLERequestContext& ctx); + void CreateApplicationArea(HLERequestContext& ctx); + void GetTagInfo(HLERequestContext& ctx); + void GetRegisterInfo(HLERequestContext& ctx); + void GetCommonInfo(HLERequestContext& ctx); + void GetModelInfo(HLERequestContext& ctx); + void AttachActivateEvent(HLERequestContext& ctx); + void AttachDeactivateEvent(HLERequestContext& ctx); + void GetState(HLERequestContext& ctx); + void GetDeviceState(HLERequestContext& ctx); + void GetNpadId(HLERequestContext& ctx); + void GetApplicationAreaSize(HLERequestContext& ctx); + void AttachAvailabilityChangeEvent(HLERequestContext& ctx); + void RecreateApplicationArea(HLERequestContext& ctx); + +private: + enum class State : u32 { + NonInitialized, + Initialized, + }; + + std::optional> GetNfpDevice(u64 handle); + + KernelHelpers::ServiceContext service_context; + + std::array, 10> devices{}; + + State state{State::NonInitialized}; + Kernel::KEvent* availability_change_event; +}; + +} // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp deleted file mode 100644 index 4e8534113..000000000 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ /dev/null @@ -1,672 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/logging/log.h" -#include "core/core.h" -#include "core/hid/hid_types.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/nfp/nfp_device.h" -#include "core/hle/service/nfp/nfp_result.h" -#include "core/hle/service/nfp/nfp_user.h" - -namespace Service::NFP { - -IUser::IUser(Core::System& system_) - : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name} { - static const FunctionInfo functions[] = { - {0, &IUser::Initialize, "Initialize"}, - {1, &IUser::Finalize, "Finalize"}, - {2, &IUser::ListDevices, "ListDevices"}, - {3, &IUser::StartDetection, "StartDetection"}, - {4, &IUser::StopDetection, "StopDetection"}, - {5, &IUser::Mount, "Mount"}, - {6, &IUser::Unmount, "Unmount"}, - {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, - {8, &IUser::GetApplicationArea, "GetApplicationArea"}, - {9, &IUser::SetApplicationArea, "SetApplicationArea"}, - {10, &IUser::Flush, "Flush"}, - {11, &IUser::Restore, "Restore"}, - {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, - {13, &IUser::GetTagInfo, "GetTagInfo"}, - {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, - {15, &IUser::GetCommonInfo, "GetCommonInfo"}, - {16, &IUser::GetModelInfo, "GetModelInfo"}, - {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, - {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, - {19, &IUser::GetState, "GetState"}, - {20, &IUser::GetDeviceState, "GetDeviceState"}, - {21, &IUser::GetNpadId, "GetNpadId"}, - {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, - {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, - {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"}, - }; - RegisterHandlers(functions); - - availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); - - for (u32 device_index = 0; device_index < 10; device_index++) { - devices[device_index] = - std::make_shared(Core::HID::IndexToNpadIdType(device_index), system, - service_context, availability_change_event); - } -} - -IUser ::~IUser() { - availability_change_event->Close(); -} - -void IUser::Initialize(HLERequestContext& ctx) { - LOG_INFO(Service_NFP, "called"); - - state = State::Initialized; - - for (auto& device : devices) { - device->Initialize(); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IUser::Finalize(HLERequestContext& ctx) { - LOG_INFO(Service_NFP, "called"); - - state = State::NonInitialized; - - for (auto& device : devices) { - device->Finalize(); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void IUser::ListDevices(HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - if (!ctx.CanWriteBuffer()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - - if (ctx.GetWriteBufferSize() == 0) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - - std::vector nfp_devices; - const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements(); - - for (const auto& device : devices) { - if (nfp_devices.size() >= max_allowed_devices) { - continue; - } - if (device->GetCurrentState() != DeviceState::Unavailable) { - nfp_devices.push_back(device->GetHandle()); - } - } - - if (nfp_devices.empty()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - ctx.WriteBuffer(nfp_devices); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(nfp_devices.size())); -} - -void IUser::StartDetection(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto nfp_protocol{rp.PopEnum()}; - LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->StartDetection(nfp_protocol); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::StopDetection(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->StopDetection(); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::Mount(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto model_type{rp.PopEnum()}; - const auto mount_target{rp.PopEnum()}; - LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle, - model_type, mount_target); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->Mount(mount_target); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::Unmount(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->Unmount(); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::OpenApplicationArea(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto access_id{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->OpenApplicationArea(access_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::GetApplicationArea(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto data_size = ctx.GetWriteBufferSize(); - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - if (!ctx.CanWriteBuffer()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - std::vector data(data_size); - const auto result = device.value()->GetApplicationArea(data); - ctx.WriteBuffer(data); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push(static_cast(data_size)); -} - -void IUser::SetApplicationArea(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto data{ctx.ReadBuffer()}; - LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size()); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - if (!ctx.CanReadBuffer()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->SetApplicationArea(data); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::Flush(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->Flush(); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::Restore(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->RestoreAmiibo(); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::CreateApplicationArea(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto access_id{rp.Pop()}; - const auto data{ctx.ReadBuffer()}; - LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, - access_id, data.size()); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - if (!ctx.CanReadBuffer()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(InvalidArgument); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->CreateApplicationArea(access_id, data); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::GetTagInfo(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - TagInfo tag_info{}; - const auto result = device.value()->GetTagInfo(tag_info); - ctx.WriteBuffer(tag_info); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::GetRegisterInfo(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - RegisterInfo register_info{}; - const auto result = device.value()->GetRegisterInfo(register_info); - ctx.WriteBuffer(register_info); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::GetCommonInfo(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - CommonInfo common_info{}; - const auto result = device.value()->GetCommonInfo(common_info); - ctx.WriteBuffer(common_info); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::GetModelInfo(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - ModelInfo model_info{}; - const auto result = device.value()->GetModelInfo(model_info); - ctx.WriteBuffer(model_info); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void IUser::AttachActivateEvent(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(device.value()->GetActivateEvent()); -} - -void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(device.value()->GetDeactivateEvent()); -} - -void IUser::GetState(HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(state); -} - -void IUser::GetDeviceState(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(device.value()->GetCurrentState()); -} - -void IUser::GetNpadId(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(device.value()->GetNpadId()); -} - -void IUser::GetApplicationAreaSize(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(device.value()->GetApplicationAreaSize()); -} - -void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { - LOG_INFO(Service_NFP, "called"); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(availability_change_event->GetReadableEvent()); -} - -void IUser::RecreateApplicationArea(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto device_handle{rp.Pop()}; - const auto access_id{rp.Pop()}; - const auto data{ctx.ReadBuffer()}; - LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle, - access_id, data.size()); - - if (state == State::NonInitialized) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(NfcDisabled); - return; - } - - auto device = GetNfpDevice(device_handle); - - if (!device.has_value()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(DeviceNotFound); - return; - } - - const auto result = device.value()->RecreateApplicationArea(access_id, data); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -std::optional> IUser::GetNfpDevice(u64 handle) { - for (auto& device : devices) { - if (device->GetHandle() == handle) { - return device; - } - } - return std::nullopt; -} - -} // namespace Service::NFP diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h deleted file mode 100644 index 1f3ff2ea8..000000000 --- a/src/core/hle/service/nfp/nfp_user.h +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include - -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/service.h" - -namespace Service::NFP { -class NfpDevice; - -class IUser final : public ServiceFramework { -public: - explicit IUser(Core::System& system_); - ~IUser(); - -private: - enum class State : u32 { - NonInitialized, - Initialized, - }; - - void Initialize(HLERequestContext& ctx); - void Finalize(HLERequestContext& ctx); - void ListDevices(HLERequestContext& ctx); - void StartDetection(HLERequestContext& ctx); - void StopDetection(HLERequestContext& ctx); - void Mount(HLERequestContext& ctx); - void Unmount(HLERequestContext& ctx); - void OpenApplicationArea(HLERequestContext& ctx); - void GetApplicationArea(HLERequestContext& ctx); - void SetApplicationArea(HLERequestContext& ctx); - void Flush(HLERequestContext& ctx); - void Restore(HLERequestContext& ctx); - void CreateApplicationArea(HLERequestContext& ctx); - void GetTagInfo(HLERequestContext& ctx); - void GetRegisterInfo(HLERequestContext& ctx); - void GetCommonInfo(HLERequestContext& ctx); - void GetModelInfo(HLERequestContext& ctx); - void AttachActivateEvent(HLERequestContext& ctx); - void AttachDeactivateEvent(HLERequestContext& ctx); - void GetState(HLERequestContext& ctx); - void GetDeviceState(HLERequestContext& ctx); - void GetNpadId(HLERequestContext& ctx); - void GetApplicationAreaSize(HLERequestContext& ctx); - void AttachAvailabilityChangeEvent(HLERequestContext& ctx); - void RecreateApplicationArea(HLERequestContext& ctx); - - std::optional> GetNfpDevice(u64 handle); - - KernelHelpers::ServiceContext service_context; - - std::array, 10> devices{}; - - State state{State::NonInitialized}; - Kernel::KEvent* availability_change_event; -}; - -} // namespace Service::NFP -- cgit v1.2.3 From 00800d5289f580ffebd38f18d1c3d7e024fc3b16 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 13 Apr 2023 20:55:47 -0600 Subject: service: nfp: Implement system interface --- src/core/hle/service/nfp/nfp.cpp | 32 ++--- src/core/hle/service/nfp/nfp_device.cpp | 52 +++++++- src/core/hle/service/nfp/nfp_device.h | 2 + src/core/hle/service/nfp/nfp_interface.cpp | 202 +++++++++++++++++++++++++++++ src/core/hle/service/nfp/nfp_interface.h | 9 ++ src/core/hle/service/nfp/nfp_types.h | 9 ++ 6 files changed, 289 insertions(+), 17 deletions(-) diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index e57e932c8..8a7365f17 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -51,8 +51,8 @@ public: explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "InitializeSystem"}, - {1, nullptr, "FinalizeSystem"}, + {0, &ISystem::InitializeSystem, "InitializeSystem"}, + {1, &ISystem::FinalizeSystem, "FinalizeSystem"}, {2, &ISystem::ListDevices, "ListDevices"}, {3, &ISystem::StartDetection, "StartDetection"}, {4, &ISystem::StopDetection, "StopDetection"}, @@ -71,13 +71,13 @@ public: {20, &ISystem::GetDeviceState, "GetDeviceState"}, {21, &ISystem::GetNpadId, "GetNpadId"}, {23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, - {100, nullptr, "Format"}, - {101, nullptr, "GetAdminInfo"}, - {102, nullptr, "GetRegisterInfoPrivate"}, - {103, nullptr, "SetRegisterInfoPrivate"}, - {104, nullptr, "DeleteRegisterInfo"}, - {105, nullptr, "DeleteApplicationArea"}, - {106, nullptr, "ExistsApplicationArea"}, + {100, &ISystem::Format, "Format"}, + {101, &ISystem::GetAdminInfo, "GetAdminInfo"}, + {102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"}, + {103, &ISystem::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"}, + {104, &ISystem::DeleteRegisterInfo, "DeleteRegisterInfo"}, + {105, &ISystem::DeleteApplicationArea, "DeleteApplicationArea"}, + {106, &ISystem::ExistsApplicationArea, "ExistsApplicationArea"}, }; // clang-format on @@ -115,13 +115,13 @@ public: {22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"}, {23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, {24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"}, - {100, nullptr, "Format"}, - {101, nullptr, "GetAdminInfo"}, - {102, nullptr, "GetRegisterInfoPrivate"}, - {103, nullptr, "SetRegisterInfoPrivate"}, - {104, nullptr, "DeleteRegisterInfo"}, - {105, nullptr, "DeleteApplicationArea"}, - {106, nullptr, "ExistsApplicationArea"}, + {100, &IDebug::Format, "Format"}, + {101, &IDebug::GetAdminInfo, "GetAdminInfo"}, + {102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"}, + {103, &IDebug::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"}, + {104, &IDebug::DeleteRegisterInfo, "DeleteRegisterInfo"}, + {105, &IDebug::DeleteApplicationArea, "DeleteApplicationArea"}, + {106, &IDebug::ExistsApplicationArea, "ExistsApplicationArea"}, {200, nullptr, "GetAll"}, {201, nullptr, "SetAll"}, {202, nullptr, "FlushDebug"}, diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 607e70968..5ed6d4181 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -29,7 +29,6 @@ #include "core/hle/service/nfp/amiibo_crypto.h" #include "core/hle/service/nfp/nfp_device.h" #include "core/hle/service/nfp/nfp_result.h" -#include "core/hle/service/nfp/nfp_user.h" #include "core/hle/service/time/time_manager.h" #include "core/hle/service/time/time_zone_content_manager.h" #include "core/hle/service/time/time_zone_types.h" @@ -417,6 +416,38 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { return ResultSuccess; } +Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + if (tag_data.settings.settings.amiibo_initialized == 0) { + return RegistrationIsNotInitialized; + } + + Service::Mii::MiiManager manager; + const auto& settings = tag_data.settings; + + // TODO: Validate and complete this data + register_info = { + .mii_store_data = {}, + .creation_date = settings.init_date.GetWriteDate(), + .amiibo_name = GetAmiiboName(settings), + .font_region = settings.settings.font_region, + }; + + return ResultSuccess; +} + Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); @@ -807,6 +838,25 @@ Result NfpDevice::DeleteApplicationArea() { return Flush(); } +Result NfpDevice::ExistApplicationArea(bool& has_application_area) { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0; + + return ResultSuccess; +} + u64 NfpDevice::GetHandle() const { // Generate a handle based of the npad id return static_cast(npad_id); diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 7f963730d..0d778c1d7 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -47,6 +47,7 @@ public: Result GetCommonInfo(CommonInfo& common_info) const; Result GetModelInfo(ModelInfo& model_info) const; Result GetRegisterInfo(RegisterInfo& register_info) const; + Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const; Result GetAdminInfo(AdminInfo& admin_info) const; Result DeleteRegisterInfo(); @@ -61,6 +62,7 @@ public: Result CreateApplicationArea(u32 access_id, std::span data); Result RecreateApplicationArea(u32 access_id, std::span data); Result DeleteApplicationArea(); + Result ExistApplicationArea(bool& has_application_area); u64 GetHandle() const; u32 GetApplicationAreaSize() const; diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp index e131703cb..d60f3cb97 100644 --- a/src/core/hle/service/nfp/nfp_interface.cpp +++ b/src/core/hle/service/nfp/nfp_interface.cpp @@ -40,6 +40,19 @@ void Interface::Initialize(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Interface::InitializeSystem(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + state = State::Initialized; + + for (auto& device : devices) { + device->Initialize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void Interface::Finalize(HLERequestContext& ctx) { LOG_INFO(Service_NFP, "called"); @@ -53,6 +66,19 @@ void Interface::Finalize(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Interface::FinalizeSystem(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + state = State::NonInitialized; + + for (auto& device : devices) { + device->Finalize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void Interface::ListDevices(HLERequestContext& ctx) { LOG_DEBUG(Service_NFP, "called"); @@ -631,6 +657,182 @@ void Interface::RecreateApplicationArea(HLERequestContext& ctx) { rb.Push(result); } +void Interface::Format(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->Format(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetAdminInfo(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + AdminInfo admin_info{}; + const auto result = device.value()->GetAdminInfo(admin_info); + ctx.WriteBuffer(admin_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + RegisterInfoPrivate register_info{}; + const auto result = device.value()->GetRegisterInfoPrivate(register_info); + ctx.WriteBuffer(register_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto buffer{ctx.ReadBuffer()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle, + buffer.size()); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->SetRegisterInfoPrivate({}); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::DeleteRegisterInfo(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->DeleteRegisterInfo(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::DeleteApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->DeleteApplicationArea(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::ExistsApplicationArea(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + bool has_application_area = false; + const auto result = device.value()->ExistApplicationArea(has_application_area); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.Push(has_application_area); +} + std::optional> Interface::GetNfpDevice(u64 handle) { for (auto& device : devices) { if (device->GetHandle() == handle) { diff --git a/src/core/hle/service/nfp/nfp_interface.h b/src/core/hle/service/nfp/nfp_interface.h index 11f29c2ba..4affdbc0c 100644 --- a/src/core/hle/service/nfp/nfp_interface.h +++ b/src/core/hle/service/nfp/nfp_interface.h @@ -19,7 +19,9 @@ public: ~Interface() override; void Initialize(HLERequestContext& ctx); + void InitializeSystem(HLERequestContext& ctx); void Finalize(HLERequestContext& ctx); + void FinalizeSystem(HLERequestContext& ctx); void ListDevices(HLERequestContext& ctx); void StartDetection(HLERequestContext& ctx); void StopDetection(HLERequestContext& ctx); @@ -43,6 +45,13 @@ public: void GetApplicationAreaSize(HLERequestContext& ctx); void AttachAvailabilityChangeEvent(HLERequestContext& ctx); void RecreateApplicationArea(HLERequestContext& ctx); + void Format(HLERequestContext& ctx); + void GetAdminInfo(HLERequestContext& ctx); + void GetRegisterInfoPrivate(HLERequestContext& ctx); + void SetRegisterInfoPrivate(HLERequestContext& ctx); + void DeleteRegisterInfo(HLERequestContext& ctx); + void DeleteApplicationArea(HLERequestContext& ctx); + void ExistsApplicationArea(HLERequestContext& ctx); private: enum class State : u32 { diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 70c878552..90429baa2 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -354,6 +354,15 @@ struct RegisterInfo { }; static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); +struct RegisterInfoPrivate { + Service::Mii::MiiStoreData mii_store_data; + WriteDate creation_date; + AmiiboName amiibo_name; + u8 font_region; + INSERT_PADDING_BYTES(0x8E); +}; +static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); + struct AdminInfo { u64 application_id; u32 application_area_id; -- cgit v1.2.3 From 307371e01d403c376a030d3a708d808659394bf5 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 13 Apr 2023 22:23:49 -0600 Subject: service: nfp: Implement debug Interface --- src/core/hle/service/nfp/nfp.cpp | 12 +- src/core/hle/service/nfp/nfp_device.cpp | 172 +++++++++++++++++++++++- src/core/hle/service/nfp/nfp_device.h | 10 ++ src/core/hle/service/nfp/nfp_interface.cpp | 204 +++++++++++++++++++++++++++++ src/core/hle/service/nfp/nfp_interface.h | 9 ++ src/core/hle/service/nfp/nfp_types.h | 45 +++++++ 6 files changed, 444 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 8a7365f17..2714f4bea 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -90,8 +90,8 @@ public: explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "InitializeDebug"}, - {1, nullptr, "FinalizeDebug"}, + {0, &IDebug::InitializeDebug, "InitializeDebug"}, + {1, &IDebug::FinalizeDebug, "FinalizeDebug"}, {2, &IDebug::ListDevices, "ListDevices"}, {3, &IDebug::StartDetection, "StartDetection"}, {4, &IDebug::StopDetection, "StopDetection"}, @@ -122,10 +122,10 @@ public: {104, &IDebug::DeleteRegisterInfo, "DeleteRegisterInfo"}, {105, &IDebug::DeleteApplicationArea, "DeleteApplicationArea"}, {106, &IDebug::ExistsApplicationArea, "ExistsApplicationArea"}, - {200, nullptr, "GetAll"}, - {201, nullptr, "SetAll"}, - {202, nullptr, "FlushDebug"}, - {203, nullptr, "BreakTag"}, + {200, &IDebug::GetAll, "GetAll"}, + {201, &IDebug::SetAll, "SetAll"}, + {202, &IDebug::FlushDebug, "FlushDebug"}, + {203, &IDebug::BreakTag, "BreakTag"}, {204, nullptr, "ReadBackupData"}, {205, nullptr, "WriteBackupData"}, {206, nullptr, "WriteNtf"}, diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 5ed6d4181..3f9af53c8 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -240,6 +240,42 @@ Result NfpDevice::Flush() { tag_data.write_counter++; + FlushWithBreak(BreakType::Normal); + + is_data_moddified = false; + + return ResultSuccess; +} + +Result NfpDevice::FlushDebug() { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + tag_data.write_counter++; + + FlushWithBreak(BreakType::Normal); + + is_data_moddified = false; + + return ResultSuccess; +} + +Result NfpDevice::FlushWithBreak(BreakType break_type) { + if (break_type != BreakType::Normal) { + LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type); + return WrongDeviceState; + } + std::vector data(sizeof(EncryptedNTAG215File)); if (is_plain_amiibo) { memcpy(data.data(), &tag_data, sizeof(tag_data)); @@ -257,8 +293,6 @@ Result NfpDevice::Flush() { return WriteAmiiboFailed; } - is_data_moddified = false; - return ResultSuccess; } @@ -857,6 +891,140 @@ Result NfpDevice::ExistApplicationArea(bool& has_application_area) { return ResultSuccess; } +Result NfpDevice::GetAll(NfpData& data) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + CommonInfo common_info{}; + Service::Mii::MiiManager manager; + const u64 application_id = tag_data.application_id; + + GetCommonInfo(common_info); + + data = { + .magic = tag_data.constant_value, + .write_counter = tag_data.write_counter, + .settings_crc = tag_data.settings.crc, + .common_info = common_info, + .mii_char_info = tag_data.owner_mii, + .mii_store_data_extension = tag_data.mii_extension, + .creation_date = tag_data.settings.init_date.GetWriteDate(), + .amiibo_name = tag_data.settings.amiibo_name, + .amiibo_name_null_terminated = 0, + .settings = tag_data.settings.settings, + .unknown1 = tag_data.unknown, + .register_info_crc = tag_data.register_info_crc, + .unknown2 = tag_data.unknown2, + .application_id = application_id, + .access_id = tag_data.application_area_id, + .settings_crc_counter = tag_data.settings.crc_counter, + .font_region = tag_data.settings.settings.font_region, + .tag_type = PackedTagType::Type2, + .console_type = + static_cast(application_id >> application_id_version_offset & 0xf), + .application_id_byte = tag_data.application_id_byte, + .application_area = tag_data.application_area, + }; + + return ResultSuccess; +} + +Result NfpDevice::SetAll(const NfpData& data) { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + tag_data.constant_value = data.magic; + tag_data.write_counter = data.write_counter; + tag_data.settings.crc = data.settings_crc; + tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date); + tag_data.write_counter = data.common_info.write_counter; + tag_data.amiibo_version = data.common_info.version; + tag_data.owner_mii = data.mii_char_info; + tag_data.mii_extension = data.mii_store_data_extension; + tag_data.settings.init_date.SetWriteDate(data.creation_date); + tag_data.settings.amiibo_name = data.amiibo_name; + tag_data.settings.settings = data.settings; + tag_data.unknown = data.unknown1; + tag_data.register_info_crc = data.register_info_crc; + tag_data.unknown2 = data.unknown2; + tag_data.application_id = data.application_id; + tag_data.application_area_id = data.access_id; + tag_data.settings.crc_counter = data.settings_crc_counter; + tag_data.settings.settings.font_region.Assign(data.font_region); + tag_data.application_id_byte = data.application_id_byte; + tag_data.application_area = data.application_area; + + return ResultSuccess; +} + +Result NfpDevice::BreakTag(BreakType break_type) { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + // TODO: Complete this implementation + + return FlushWithBreak(break_type); +} + +Result NfpDevice::ReadBackupData() { + // Not implemented + return ResultSuccess; +} + +Result NfpDevice::WriteBackupData() { + // Not implemented + return ResultSuccess; +} + +Result NfpDevice::WriteNtf() { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + // Not implemented + + return ResultSuccess; +} + u64 NfpDevice::GetHandle() const { // Generate a handle based of the npad id return static_cast(npad_id); diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 0d778c1d7..bab05538a 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -41,7 +41,10 @@ public: Result StopDetection(); Result Mount(MountTarget mount_target); Result Unmount(); + Result Flush(); + Result FlushDebug(); + Result FlushWithBreak(BreakType break_type); Result GetTagInfo(TagInfo& tag_info) const; Result GetCommonInfo(CommonInfo& common_info) const; @@ -64,6 +67,13 @@ public: Result DeleteApplicationArea(); Result ExistApplicationArea(bool& has_application_area); + Result GetAll(NfpData& data) const; + Result SetAll(const NfpData& data); + Result BreakTag(BreakType break_type); + Result ReadBackupData(); + Result WriteBackupData(); + Result WriteNtf(); + u64 GetHandle() const; u32 GetApplicationAreaSize() const; DeviceState GetCurrentState() const; diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp index d60f3cb97..2ed8bb1ba 100644 --- a/src/core/hle/service/nfp/nfp_interface.cpp +++ b/src/core/hle/service/nfp/nfp_interface.cpp @@ -53,6 +53,19 @@ void Interface::InitializeSystem(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Interface::InitializeDebug(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + state = State::Initialized; + + for (auto& device : devices) { + device->Initialize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void Interface::Finalize(HLERequestContext& ctx) { LOG_INFO(Service_NFP, "called"); @@ -79,6 +92,19 @@ void Interface::FinalizeSystem(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Interface::FinalizeDebug(HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); + + state = State::NonInitialized; + + for (auto& device : devices) { + device->Finalize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void Interface::ListDevices(HLERequestContext& ctx) { LOG_DEBUG(Service_NFP, "called"); @@ -833,6 +859,184 @@ void Interface::ExistsApplicationArea(HLERequestContext& ctx) { rb.Push(has_application_area); } +void Interface::GetAll(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + NfpData data{}; + const auto result = device.value()->GetAll(data); + + ctx.WriteBuffer(data); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::SetAll(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto nfp_data{ctx.ReadBuffer()}; + + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + NfpData data{}; + memcpy(&data, nfp_data.data(), sizeof(NfpData)); + + const auto result = device.value()->SetAll(data); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::FlushDebug(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->FlushDebug(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::BreakTag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + const auto break_type{rp.PopEnum()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}, break_type={}", device_handle, break_type); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->BreakTag(break_type); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::ReadBackupData(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->ReadBackupData(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::WriteBackupData(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->WriteBackupData(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void Interface::WriteNtf(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfpDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->WriteNtf(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + std::optional> Interface::GetNfpDevice(u64 handle) { for (auto& device : devices) { if (device->GetHandle() == handle) { diff --git a/src/core/hle/service/nfp/nfp_interface.h b/src/core/hle/service/nfp/nfp_interface.h index 4affdbc0c..616c94b06 100644 --- a/src/core/hle/service/nfp/nfp_interface.h +++ b/src/core/hle/service/nfp/nfp_interface.h @@ -20,8 +20,10 @@ public: void Initialize(HLERequestContext& ctx); void InitializeSystem(HLERequestContext& ctx); + void InitializeDebug(HLERequestContext& ctx); void Finalize(HLERequestContext& ctx); void FinalizeSystem(HLERequestContext& ctx); + void FinalizeDebug(HLERequestContext& ctx); void ListDevices(HLERequestContext& ctx); void StartDetection(HLERequestContext& ctx); void StopDetection(HLERequestContext& ctx); @@ -52,6 +54,13 @@ public: void DeleteRegisterInfo(HLERequestContext& ctx); void DeleteApplicationArea(HLERequestContext& ctx); void ExistsApplicationArea(HLERequestContext& ctx); + void GetAll(HLERequestContext& ctx); + void SetAll(HLERequestContext& ctx); + void FlushDebug(HLERequestContext& ctx); + void BreakTag(HLERequestContext& ctx); + void ReadBackupData(HLERequestContext& ctx); + void WriteBackupData(HLERequestContext& ctx); + void WriteNtf(HLERequestContext& ctx); private: enum class State : u32 { diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 90429baa2..1ef047cee 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -109,6 +109,12 @@ enum class AppAreaVersion : u8 { NotSet = 0xFF, }; +enum class BreakType : u32 { + Normal, + Unknown1, + Unknown2, +}; + enum class CabinetMode : u8 { StartNicknameAndOwnerSettings, StartGameDataEraser, @@ -181,6 +187,12 @@ struct AmiiboDate { }; } + void SetWriteDate(const WriteDate& write_date) { + SetYear(write_date.year); + SetMonth(write_date.month); + SetDay(write_date.day); + } + void SetYear(u16 year) { const u16 year_converted = static_cast((year - 2000) << 9); raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); @@ -375,6 +387,39 @@ struct AdminInfo { }; static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size"); +#pragma pack(1) +// This is nn::nfp::NfpData +struct NfpData { + u8 magic; + INSERT_PADDING_BYTES(0x1); + u8 write_counter; + INSERT_PADDING_BYTES(0x1); + u32 settings_crc; + INSERT_PADDING_BYTES(0x38); + CommonInfo common_info; + Service::Mii::Ver3StoreData mii_char_info; + Service::Mii::NfpStoreDataExtension mii_store_data_extension; + WriteDate creation_date; + std::array amiibo_name; + u16 amiibo_name_null_terminated; + Settings settings; + u8 unknown1; + u32 register_info_crc; + std::array unknown2; + INSERT_PADDING_BYTES(0x64); + u64 application_id; + u32 access_id; + u16 settings_crc_counter; + u8 font_region; + PackedTagType tag_type; + AppAreaVersion console_type; + u8 application_id_byte; + INSERT_PADDING_BYTES(0x2E); + ApplicationArea application_area; +}; +static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); +#pragma pack() + struct SectorKey { MifareCmd command; u8 unknown; // Usually 1 -- cgit v1.2.3